# -*- coding: UTF-8 -*-
"""
By AnpyD
防御塔
"""

import bs
import bsSpaz
import random
import tower_bomb as towerBomb

class ProtectShield(bs.Actor):
    def __init__(self, position, color, radius, source_player):
        bs.Actor.__init__(self)

        self.position = position
        self.color = (color[0]+1, color[1]+1, color[2]+1)
        self.radius = radius
        self.source_player = source_player
        self.Material = bs.Material()

        self.Material.addActions(conditions=(('theyHaveMaterial', bs.getSharedObject('playerMaterial'))),
                                actions=(('modifyPartCollision', 'collide', True),
                                        ('modifyPartCollision', 'physical', False),
                                        ('call', 'atConnect', self.touchedSpaz)))

        self.node = bs.newNode("region", attrs={'position': (self.position[0],
                                                            self.position[1],
                                                            self.position[2]),
                                                'scale': (self.radius, self.radius, self.radius),
                                                'type': 'sphere', 
                                                'materials':[self.Material]})

        self.shield = bs.newNode("shield", attrs={"position": self.position, "color": self.color, "radius":0.1})

        bs.animate(self.shield, "radius", {0: 0.1, 300:1.9, 600:1.4, 900:1.6})

        bs.gameTimer(1000, self.node.delete)
        bs.gameTimer(1000, self.shield.delete)

    def touchedSpaz(self):
        node = bs.getCollisionInfo('opposingNode')
        node.handleMessage(bs.HitMessage(
                            pos=node.position,
                            velocity=(10, 10, 10),
                            magnitude=5,
                            velocityMagnitude=5,
                            sourcePlayer=self.source_player,
                            radius=0))
        bs.emitBGDynamics(
            position=node.position,
            count=20,
            scale=0.5,
            spread=0.5,
            chunkType='spark')


class Tower(bs.Actor):
    def __init__(self, position=(0, 5, 0), radius=4, source_player=None, owner=None, color=(0, 0, 1), hit_point_max=650, stand_time=900):
        bs.Actor.__init__(self)
        self.position = position
        self.radius = radius
        self.source_player = source_player
        self.owner = owner
        self.color = color
        self._owner_name = ""
        self.hp = self.hit_point_max = hit_point_max
        self.stand_time = stand_time
        
        try:
            self.team = self.owner.getDelegate().getPlayer().getTeam()
        except:
            self.team = None

        if owner is None:
            text = "AnpyD's Tower Fighter"
        else:
            self.color = (self.team.color[0], self.team.color[1], self.team.color[2])
            text = self.owner.name + "'s Tower Fighter"
            self._owner_name = self.owner.name

        self.aim = bs.Material()
        self.aim.addActions(
            conditions=(('theyHaveMaterial', 
                         bs.getSharedObject('objectMaterial'))),
            actions=(('modifyPartCollision', 'collide', True),
                     ('modifyPartCollision', 'physical', False),
                     ('call', 'atConnect', self.decide)))

        self.flag = bs.newNode('flag', 
                                delegate=self, 
                                attrs={
                                'colorTexture':bs.getTexture(random.choice(['agentIcon', 'aliIcon', 'bearIcon'])),
                                'color':self.color,
                                'position':position,
                                'materials':[bs.getSharedObject('objectMaterial'),
                                            bs.getSharedObject('footingMaterial')]})
        
        self.region = bs.newNode('region', 
                                owner=self.flag, 
                                attrs={'position':self.flag.position,
                                        'scale': (self.radius, self.radius, self.radius),
                                        'type': 'sphere',
                                        'materials': [self.aim]})

        self.light = bs.newNode('light', 
                                owner=self.flag, 
                                attrs={'intensity':0.45, 
                                        'color':self.color,
                                        'position':self.flag.position, 
                                        'radius':0})
        
        self.flash = bs.newNode('flash', 
                                attrs={
                                'position': self.flag.position,
                                'color': self.color,
                                'size': 0.2})

        self.shield = bs.newNode('shield', 
                                attrs={'color':self.color, 
                                        'position':self.flag.position, 
                                        'radius':0})

        self.text = bs.newNode('text',
                                 owner=self.flag, 
                                 attrs={'text':text, 
                                        'inWorld':True, 
                                        'flatness':0.2, 
                                        'color':self.color, 
                                        'scale':0.006, 
                                        'hAlign':'center'})
        # For Flash                    
        self.math = bs.newNode('math', owner=self.flag, attrs={'input1':(0, 1.0, 0), 'operation':'add'})
        # For Shield(Decay Bar)
        self.math1 = bs.newNode('math', owner=self.flag, attrs={'input1':(0, 0.5, 0), 'operation':'add'})
        # For Text
        self.math2 = bs.newNode('math', owner=self.flag, attrs={'input1':(0, 1.3, 0), 'operation':'add'})

        # Decay Bar
        self.shield.alwaysShowHealthBar = True

        self.flag.connectAttr('position', self.math, 'input2')
        self.flag.connectAttr('position', self.math1, 'input2')
        self.flag.connectAttr('position', self.math2, 'input2')
        self.flag.connectAttr('position', self.light, 'position')
        self.flag.connectAttr('position', self.region, 'position')

        self.math.connectAttr('output', self.flash, 'position')
        self.math1.connectAttr('output',self.shield, 'position')
        self.math2.connectAttr('output', self.text, 'position')

        bs.animateArray(self.region, 'scale', 3, {0:(0,0,0), 100:(self.radius, self.radius, self.radius)})

        self.timer()

    def timer(self):
        bs.animateArray(self.region, 
                        'scale', 
                        3, 
                        {0:(0, 0, 0), 
                        self.stand_time-100:(0, 0, 0), 
                        self.stand_time:(self.radius, self.radius, self.radius)}, 
                        True)

    def decay_bar(self, hit_point):
        if self.shield is not None and self.shield.exists():
            self.hp = max(0, self.hp - hit_point)
            self.shield.hurt = 1.0 - float(self.hp)/self.hit_point_max

    def delete(self):
        bs.Blast(position=self.flag.position, blastRadius=3)
        bs.emitBGDynamics(position=self.flag.position, 
                                  count=int(random.randint(12, 30)), 
                                  scale=0.4,
                                  chunkType='metal')
        bs.emitBGDynamics(position=self.flag.position,
                              count=int(1.0+random.random()*4),
                              emitType='tendrils',tendrilType='thinSmoke')
        self.flash.delete()
        self.text.delete()
        self.shield.delete()
        self.flag.delete()

    def launch(self, node):
        velocity = tuple((node.position[index]-i)*2.23 for index,i in enumerate(self.flag.position))
        towerBomb.Bomb(position=(self.flag.position[0], self.flag.position[1]+1.3, self.flag.position[2]), 
                        sourcePlayer=self.source_player, 
                        owner=self.owner, 
                        velocity=velocity).autoRetain()
        bs.animate(self.light, 'radius', {0:0.3, 500:0.3, 900:0.3, 1000:0})
        bs.animate(self.flash, 'size', {0:0.2,250:0.5,500:0.2})

        hit_point = random.randint(10, 30)
        self.decay_bar(hit_point)
        if self.hp <= 0:
                self.delete()
        
        self.timer()

    def decide(self):
        node = bs.getCollisionInfo('opposingNode')
        source = node.getDelegate()
        if isinstance(source, bsSpaz.Spaz):
            try:
                if self.team is not None:
                    # Team
                    if node is not None and node.exists():
                        if node.getDelegate().getPlayer().getTeam() != self.team:
                            self.launch(node)
                else:
                    # FFA
                    if node.exists() and node != self.owner:
                        self.launch(node)
            except Exception as e:
                pass
        
        else:
            pass

    def handleMessage(self, msg):
        if isinstance(msg, bs.PickedUpMessage):
            if msg.node.getDelegate().getPlayer().getName() != self._owner_name:
                msg.node.getDelegate().onPunchPress()
                msg.node.getDelegate().onPickUpPress()
                msg.node.getDelegate().onPunchRelease()
                msg.node.getDelegate().onPickUpRelease()
                msg.node.getDelegate().onPickUpPress()
                msg.node.getDelegate().onPickUpRelease()
            else:
                if msg.node.getDelegate().getPlayer().getTeam() != self.team:
                    msg.node.getDelegate().onPunchPress()
                    msg.node.getDelegate().onPickUpPress()
                    msg.node.getDelegate().onPunchRelease()
                    msg.node.getDelegate().onPickUpRelease()
                    msg.node.getDelegate().onPickUpPress()
                    msg.node.getDelegate().onPickUpRelease()
                else:
                    pass
        
        if isinstance(msg, bs.OutOfBoundsMessage):
            self.delete()
        elif isinstance(msg, bs.DieMessage):
            self.delete()
        elif isinstance(msg, bs.HitMessage):
            if msg.hitType == "explosion":
                hit_point = random.randint(80, 120)
            else:
                hit_point = random.randint(20, 80)
            bs.emitBGDynamics(position=self.flag.position, 
                                  count=int(2.0+int(hit_point/2)*2), 
                                  scale=0.4,
                                  chunkType='spark')
            if hit_point > 70:
                ProtectShield(position=self.flag.position, color=self.color, radius=1, source_player=self.source_player)

            self.decay_bar(hit_point)
            if self.hp <= 0:
                self.delete()
